package cn.good.yan;

import cn.good.yan.entity.COrder;
import cn.good.yan.entity.OrderItem;
import cn.good.yan.mapper.COrderMapper;
import cn.good.yan.mapper.OrderItemMapper;
import cn.good.yan.vo.OrderVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;
import java.util.List;

/**
 * 水平分片 - 多表关联 的测试 、 绑定表
 * 引用：application5.properties 配置文件
 * 准备：server-order1 数据源中有4个表（t_order0 和 t_order1）
 * 和 server-order2 数据源中有4个表（t_order_item0 和 t_order_item1）
 *
 * @author shengren.yan
 * @create 2024/12/8
 */
@SpringBootTest
public class SplitTest5 {

    @Autowired
    private COrderMapper cOrderMapper;

    @Autowired
    private OrderItemMapper itemMapper;

    // 取模，得到奇数还是偶数
    public static void main(String[] args) {
        System.out.println(1 % 2 + 1);  // 2
        System.out.println(2 % 2 + 1);  // 1
    }

    /**
     * [分别插入 - 逻辑表 t_c_order 和 t_order_item ]
     * 多表关联  - 写入数据的测试 - 分表插入数据
     * 有2个数据库 （order1库 order2库）分别有4个表（t_order0 和 t_order1 和 t_order_item0 和 t_order_item1）表
     * 写操作，分别插入对应的数据库的sql
     * 会打印2条SQL 语句：Logic SQL（逻辑SQL） - Actual SQL（具体操作的库）
     */
    @Test
    public void testInsert() {

        // 1.先分库
        // 分片规则：表中`user_id`为偶数时，数据插入`server-order1数据源`，`user_id`为奇数时，数据插入`server-order2数据源`
        // 2.再分表
        // 分片规则：表中`order_no`是字符串，进行哈希取模，哈希值为偶数时，插入到t_order0中，奇数插入到t_order1表中

        // 1 因user_id是1，奇数，先插入到 server-order2库中
        // 2 因order_no是取模，奇数，先插入到 t_order1表中
        // 逻辑SQL（Logic SQL） ：插入 t_c_order表
        // 实际SQL（Actual SQ） ：插入 server-order2 数据源 t_order1、t_order2 表
        for (long i = 1; i < 5; i++) {
            COrder order = new COrder();
            order.setOrderNo("yanyan" + i);
            order.setUserId(1L);
            order.setAmount(new BigDecimal(i));
            cOrderMapper.insert(order);
            for (long j = 0; j < 3; j++) {
                // 创建对应的订单详情
                // t_order_item 同上，插入到`server-order2数据源`，插入的表跟上面的order_no是取模，奇数，先插入到 t_order1表中
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderNo("yanyan" + i);    // t_order_item0 跟 t_order0 同步 ，t_order_item1 跟 t_order1 同步
                orderItem.setUserId(1L);
                orderItem.setPrice(new BigDecimal(i * 10));
                orderItem.setCount(2);
                itemMapper.insert(orderItem);
            }
        }


        // 1 因user_id是2，偶数，先插入到 server-order1库中
        // 2 因order_no是取模，奇数，先插入到 t_order1表中
        // 逻辑SQL（Logic SQL） ：插入 t_c_order表
        // 实际SQL（Actual SQ） ：插入 server-order1 数据源 t_order1、t_order2 表
        for (long i = 5; i < 9; i++) {
            COrder order = new COrder();
            order.setOrderNo("yanyan" + i);
            order.setUserId(2L);
            order.setAmount(new BigDecimal(i));
            cOrderMapper.insert(order);
            for (long j = 0; j < 3; j++) {
                // 创建对应的订单详情
                // t_order_item 同上，插入到`server-order1数据源`，插入的表跟上面的order_no是取模，奇数，先插入到 t_order1表中
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderNo("yanyan" + i);  // t_order_item0 跟 t_order0 同步 ，t_order_item1 跟 t_order1 同步
                orderItem.setUserId(2L);
                orderItem.setPrice(new BigDecimal(i * 10));
                orderItem.setCount(3);
                itemMapper.insert(orderItem);
            }
        }

        // 下面的testHash，分别插入到，哈希取模后的，对应的库中
        // i 对应的 Amount，方便看下面的插入对应表的数据
        // 执行完，
        // server-order1数据源:  user_id = 1的数据 （奇数）
        //    t_order0表：（OrderNo）有： yanyan2 、yanyan4
        //    t_order1表：（OrderNo）有： yanyan1 、yanyan3
        //    t_order_item0表：（OrderNo）有： yanyan2 （有3个） 、yanyan3（有3个）
        //    t_order_item1表：（OrderNo）有： yanyan1 （有3个）、 yanyan3（有3个）
        // server-order2数据源:  user_id = 2的数据 （偶数）
        //    t_order0表：（OrderNo）有： yanyan6 、yanyan8
        //    t_order1表：（OrderNo）有： yanyan5 、yanyan7
        //    t_order_item0表：（OrderNo）有： yanyan6 （有3个） 、yanyan8（有3个）
        //    t_order_item1表：（OrderNo）有： yanyan5 （有3个）、 yanyan7（有3个）
    }


    /**
     * 分别查看他们的hash值，取模后的是：
     * --- server-order2库中
     * 1  -1    --- t_order1 表中
     * 2   0    --- t_order0
     * 3  -1    --- t_order1 表中
     * 4   0    --- t_order0
     * --------------
     * server-order1库中
     * 5  -1   --- t_order1 表中
     * 6   0   --- t_order0
     * 7  -1   --- t_order1 表中
     * 8   0   --- t_order0
     */
    @Test
    public void testHash() {
        for (long i = 1; i < 5; i++) {
            String str = "yanyan" + i;
            System.out.println(str.hashCode() % 2);
        }
        System.out.println("--------------");
        for (long i = 5; i < 9; i++) {
            String str = "yanyan" + i;
            System.out.println(str.hashCode() % 2);
        }
    }


    /**
     * 测试关联查询  - 根据 每个订单编号，总金额
     * 如果不配置绑定表，关系，
     *   - 逻辑SQL（Logic SQL） ：mapper中SQL
     *   - 实际SQL（Actual SQ）：分别查询8次  server-order1库的  t_order0  JOIN t_order_item0
     *                                    server-order1库的  t_order0  JOIN t_order_item1
     *                                    server-order1库的  t_order1  JOIN t_order_item0
     *                                    server-order1库的  t_order1  JOIN t_order_item1
     *                                    server-order2库的  t_order0  JOIN t_order_item0
     *                                    server-order2库的  t_order0  JOIN t_order_item1
     *                                    server-order2库的  t_order1  JOIN t_order_item0
     *                                    server-order2库的  t_order1  JOIN t_order_item1
     * ----------------------------------------------
     * 配置文件，配置绑定表
     * spring.shardingsphere.rules.sharding.binding-tables[0]=t_c_order,t_order_item
     *   - 逻辑SQL（Logic SQL） ：mapper中SQL
     *   - 实际SQL（Actual SQ）：分别查询4次  server-order1库的  t_order0  JOIN t_order_item0
     *                                    server-order1库的  t_order1  JOIN t_order_item1
     *                                    server-order2库的  t_order0  JOIN t_order_item0
     *                                    server-order2库的  t_order1  JOIN t_order_item1
     * （查询效率更高，查询规则，按配置文件的配置规则去查询）
     *  这也是，分库分表按，关联字段分，并不是按主键去分
     *
     */
    @Test
    public void testGetOrderAmount1() {
        List<OrderVo> orderAmountList = itemMapper.getOrderAmount();
        orderAmountList.forEach(System.out::println);
    }


}
